import type { HttpRequestOptions } from '@/types/http'
import axios from 'axios'
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
import { ElMessage, ElLoading } from 'element-plus'
import type { LoadingInstance } from 'element-plus/es/components/loading/src/loading'

type RequestMethods = 'get' | 'post' | 'put' | 'delete'

/**
 * HTTP请求类，用于封装Axios的配置和拦截器设置
 */
class HttpRequest {
  private readonly baseURL: string
  private readonly timeout: number
  private axiosInstance: AxiosInstance
  private hasLoading: boolean
  /**
   * HttpRequst构造函数
   * @param options 其他请求配置
   */
  constructor(options: HttpRequestOptions) {
    this.baseURL = options.baseUrl || import.meta.env.VITE_API_BASE_URL
    this.timeout = options.timeout || 5 * 60 * 1000
    this.hasLoading = options.hasLoading
    this.axiosInstance = this.createAxiosInstance(options.headers)
  }

  /**
   * 创建axios实例并配置拦截器
   */
  private createAxiosInstance(headers: Record<string, unknown> = {}): AxiosInstance {
    const instance = axios.create({
      baseURL: this.baseURL,
      timeout: this.timeout,
      headers: {
        'Content-Type': 'application/json',
        ...headers,
      },
    })

    this.setupInterceptors(instance)
    return instance
  }

  /**
   * 配置拦截器
   */
  private setupInterceptors(instance: AxiosInstance): void {
    // 维护loading状态的Map
    const loadingMap = new Map<string, LoadingInstance>()
    // 请求拦截器
    instance.interceptors.request.use(
      (config) => {
        if (this.hasLoading) {
          const requestId = `${config.method}_${config.url}`
          loadingMap.set(
            requestId,
            ElLoading.service({
              lock: true,
              text: '加载中...',
              background: 'rgba(0, 0, 0, 0.7)',
            })
          )
        }

        // 添加时间戳，避免缓存
        if (config.method === 'get') {
          config.params = { ...config.params }
        } else {
          config.data = { ...config.data }
        }

        // 动态获取最新 token（从 localStorage获取,因为store可能不存在）
        const token = localStorage.getItem('atlas-token')
        if (token) {
          config.headers!.Authorization = `Bearer ${token}`
        }
        return config
      },
      (error) => {
        ElMessage.error('请求配置错误：' + error.message)
        return Promise.reject(error)
      }
    )

    // 响应拦截器
    instance.interceptors.response.use(
      (response: AxiosResponse) => {
        if (this.hasLoading) {
          const requestId = `${response.config.method}_${response.config.url}`
          const loading = loadingMap.get(requestId)
          if (loading) {
            loading.close()
            loadingMap.delete(requestId)
          }
        }
        const { status, data } = response
        if (status === 200 || status === 201 || status === 204) {
          return data
        } else {
          ElMessage.error(`请求失败：${status}`)
          return Promise.reject(new Error(`HTTP状态码：${status}`))
        }
      },
      (error) => {
        if (this.hasLoading) {
          // 关闭所有loading
          loadingMap.forEach((loading) => loading?.close())
          loadingMap.clear()
        }

        // 错误处理
        if (error.response) {
          const { status } = error.response
          switch (status) {
            case 401:
              // ElMessage.error('未授权，请重新登录')
              break
            case 403:
              ElMessage.error('拒绝访问')
              break
            case 404:
              ElMessage.error('请求的资源不存在')
              break
            case 409:
              ElMessage.error('请求的资源不存在')
              break
            case 500:
              ElMessage.error('服务器错误')
              break
            default:
              ElMessage.error(`请求失败：${error.message}`)
          }
        } else if (error.request) {
          ElMessage.error('网络错误，请检查您的网络连接')
        } else {
          ElMessage.error(`请求错误：${error.message}`)
        }

        return Promise.reject(error)
      }
    )
  }

  /**
   * 创建请求配置
   */
  private createRequestConfig(
    method: RequestMethods,
    url: string,
    data?: any,
    headers: Record<string, string> = {}
  ): AxiosRequestConfig {
    const config: AxiosRequestConfig = {
      url,
      method,
      headers: {
        ...headers,
      },
    }
    if (method === 'get') {
      config.params = data
    } else {
      config.data = data //post put delete方法
    }

    return config
  }

  /**
   * 发送请求的通用方法
   */
  private async request<T = unknown>(config: AxiosRequestConfig): Promise<T> {
    try {
      return await this.axiosInstance.request<unknown, T>(config)
    } catch (error) {
      return Promise.reject(error)
    }
  }

  /**
   * GET请求
   */
  public get<T = unknown>(url: string, params?: any, headers: Record<string, string> = {}): Promise<T> {
    return this.request<T>(this.createRequestConfig('get', url, params, headers))
  }

  /**
   * POST请求
   */
  public post<T = unknown>(url: string, data?: any, headers: Record<string, string> = {}): Promise<T> {
    return this.request<T>(this.createRequestConfig('post', url, data, headers))
  }

  /**
   * PUT请求
   */
  public put<T = unknown>(url: string, data?: any, headers: Record<string, string> = {}): Promise<T> {
    return this.request<T>(this.createRequestConfig('put', url, data, headers))
  }

  /**
   * DELETE请求
   */
  public delete<T = unknown>(url: string, data?: any, headers: Record<string, string> = {}): Promise<T> {
    return this.request<T>(this.createRequestConfig('delete', url, data, headers))
  }
}

/**
 * 请求后端API接口
 */
const requestAPI = new HttpRequest({
  baseUrl: import.meta.env.VITE_BASE_API,
  headers: {
    'Content-Type': 'application/json',
  },
  hasLoading: true,
})
/**
 * 请求后端API接口
 */
const requestAPINoLoading = new HttpRequest({
  baseUrl: import.meta.env.VITE_BASE_API,
  headers: {
    'Content-Type': 'application/json',
  },
  hasLoading: false,
})
export { requestAPI, requestAPINoLoading }
